//------------------------------------------------------------------------------
//  <copyright file="FastTuple.cs" company="Microsoft Corporation">
// The MIT License (MIT)
// 
// Copyright (c) 2014, Microsoft Corporation
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//  copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//  THE SOFTWARE.
//  </copyright>
//------------------------------------------------------------------------------

namespace Microsoft.Robotics.Numerics
{
    using System;
    using System.Diagnostics;

    /// <summary>
    /// Fast tuple type that does not make assumptions about the lifetime of contained objects.
    /// </summary>
    /// <typeparam name="T1">Type of Item1</typeparam>
    /// <typeparam name="T2">Type of Item2</typeparam>
    [DebuggerDisplay("Item1={Item1}, Item2={Item2}")]
    public struct FastTuple<T1, T2> : IEquatable<FastTuple<T1, T2>>
        where T1 : IEquatable<T1>
        where T2 : IEquatable<T2>
    {
        /// <summary>
        /// Gets or sets first item 
        /// </summary>
        public T1 Item1;

        /// <summary>
        /// Gets or sets second item 
        /// </summary>
        public T2 Item2;

        /// <summary>
        /// Initializes a new instance of the FastTuple struct.
        /// </summary>
        /// <param name="that">Object to copy</param>
        public FastTuple(FastTuple<T1, T2> that) :
            this()
        {
            this.Item1 = that.Item1;
            this.Item2 = that.Item2;
        }

        /// <summary>
        /// Initializes a new instance of the FastTuple struct.
        /// </summary>
        /// <param name="item1">First item</param>
        /// <param name="item2">Second item</param>
        public FastTuple(T1 item1, T2 item2) :
            this()
        {
            this.Item1 = item1;
            this.Item2 = item2;
        }

        /// <summary>
        /// Determine equality between two tuples.
        /// </summary>
        /// <param name="a">First instance.</param>
        /// <param name="b">Second instance.</param>
        /// <returns>Indication of equality.</returns>
        public static bool operator ==(FastTuple<T1, T2> a, FastTuple<T1, T2> b)
        {
            return a.Equals(b);
        }

        /// <summary>
        /// Determine inequality between a pair of Tuples.
        /// </summary>
        /// <param name="a">First instance.</param>
        /// <param name="b">Second instance.</param>
        /// <returns>Indication of inequality.</returns>
        public static bool operator !=(FastTuple<T1, T2> a, FastTuple<T1, T2> b)
        {
            return !a.Equals(b);
        }

        /// <summary>
        /// Determine equality with another tuple.
        /// </summary>
        /// <param name="obj">Another object to which to compare.</param>
        /// <returns>Indication of equality.</returns>
        public override bool Equals(object obj)
        {
            if (obj is FastTuple<T1, T2>)
            {
                return this.Equals((FastTuple<T1, T2>)obj);
            }

            return false;
        }

        /// <summary>
        /// Determine equality with another tuple.
        /// </summary>
        /// <param name="that">Another tuple to which to compare.</param>
        /// <returns>Indication of equality.</returns>
        public bool Equals(FastTuple<T1, T2> that)
        {
            if (object.ReferenceEquals(this, that))
            {
                return true;
            }

            return this.Item1.Equals(that.Item1) && this.Item2.Equals(that.Item2);
        }

        /// <summary>
        /// Get hash code value.
        /// </summary>
        /// <returns>Hash code.</returns>
        public override int GetHashCode()
        {
            return this.Item1.GetHashCode() ^ this.Item2.GetHashCode();
        }
    }

    /// <summary>
    /// Fast tuple type that does not make assumptions about the lifetime of contained objects.
    /// </summary>
    /// <typeparam name="T1">Type of first element.</typeparam>
    /// <typeparam name="T2">Type of second element.</typeparam>
    /// <typeparam name="T3">Type of third element.</typeparam>
    [DebuggerDisplay("Item1={Item1}, Item2={Item2} Item3={Item3}")]
    public struct FastTuple<T1, T2, T3> : IEquatable<FastTuple<T1, T2, T3>>
        where T1 : IEquatable<T1>
        where T2 : IEquatable<T2>
        where T3 : IEquatable<T3>
    {
        /// <summary>
        /// Gets or sets first item 
        /// </summary>
        public T1 Item1;

        /// <summary>
        /// Gets or sets second item 
        /// </summary>
        public T2 Item2;

        /// <summary>
        /// Gets or sets second item 
        /// </summary>
        public T3 Item3;

        /// <summary>
        /// Initializes a new instance of the FastTuple struct.
        /// </summary>
        /// <param name="that">Object to copy</param>
        public FastTuple(FastTuple<T1, T2, T3> that)
        {
            this.Item1 = that.Item1;
            this.Item2 = that.Item2;
            this.Item3 = that.Item3;
        }

        /// <summary>
        /// Initializes a new instance of the FastTuple struct.
        /// </summary>
        /// <param name="item1">First item</param>
        /// <param name="item2">Second item</param>
        /// <param name="item3">Third item</param>
        public FastTuple(T1 item1, T2 item2, T3 item3) 
        {
            this.Item1 = item1;
            this.Item2 = item2;
            this.Item3 = item3;
        }

        /// <summary>
        /// Determine equality between two tuples.
        /// </summary>
        /// <param name="a">First instance.</param>
        /// <param name="b">Second instance.</param>
        /// <returns>Indication of equality.</returns>
        public static bool operator ==(FastTuple<T1, T2, T3> a, FastTuple<T1, T2, T3> b)
        {
            return a.Equals(b);
        }

        /// <summary>
        /// Determine inequality between a pair of Tuples.
        /// </summary>
        /// <param name="a">First instance.</param>
        /// <param name="b">Second instance.</param>
        /// <returns>Indication of inequality.</returns>
        public static bool operator !=(FastTuple<T1, T2, T3> a, FastTuple<T1, T2, T3> b)
        {
            return !a.Equals(b);
        }

        /// <summary>
        /// Determine equality with another tuple.
        /// </summary>
        /// <param name="obj">Another object to which to compare.</param>
        /// <returns>Indication of equality.</returns>
        public override bool Equals(object obj)
        {
            if (obj is FastTuple<T1, T2, T3>)
            {
                return this.Equals((FastTuple<T1, T2, T3>)obj);
            }

            return false;
        }

        /// <summary>
        /// Determine equality with another tuple.
        /// </summary>
        /// <param name="that">Another tuple to which to compare.</param>
        /// <returns>Indication of equality.</returns>
        public bool Equals(FastTuple<T1, T2, T3> that)
        {
            if (object.ReferenceEquals(this, that))
            {
                return true;
            }

            return this.Item1.Equals(that.Item1) && this.Item2.Equals(that.Item2) && this.Item3.Equals(that.Item3);
        }

        /// <summary>
        /// Get hash code value.
        /// </summary>
        /// <returns>Hash code.</returns>
        public override int GetHashCode()
        {
            return this.Item1.GetHashCode() ^ this.Item2.GetHashCode() ^ this.Item3.GetHashCode();
        }
    }
}
